﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Austin.HttpApi;
using System.Security.Principal;
using System.IO;
using System.Deployment.Application;
using System.Diagnostics;
using System.Text;
using System.IO.IsolatedStorage;

namespace TorrentProxy
{
	static class Program
	{
		static CommandLineArguments arguments;
		public volatile static Settings Settings;

		private const string LOGSOURCE = "dotNET Sample App";
		private const string LOGNAME = "Application";
		private const string SETTINGSFILE = "settings.xml";
		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main(string[] args)
		{            
			Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
			AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

			arguments = new CommandLineArguments(args);            

			Settings = new Settings();            
			IsolatedStorageFile isoStore = IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
				IsolatedStorageScope.Assembly | IsolatedStorageScope.Domain, null, null);
			try
			{
				if (isoStore.FileExists(SETTINGSFILE))
				{
					using (IsolatedStorageFileStream stream = isoStore.OpenFile(SETTINGSFILE, FileMode.Open))
					{
						Settings.Load(stream);
					}
				}
			}
			catch(Exception)
			{
			}

			Boolean exit = false;
			if (arguments.Parameters.ContainsKey("reserve"))
			{
				try
				{
					String url = String.Format("http://127.0.0.1:{0}/", arguments.Parameters["reserve"]);
					UrlReservation reservation = new UrlReservation(url);
					reservation.AddSecurityIdentifier(new SecurityIdentifier(WellKnownSidType.WorldSid, null));
					reservation.Create();
					exit = true;
				}
				catch (Exception)
				{
					Environment.Exit(-1);
				}
			}

			if (arguments.Parameters.ContainsKey("removeReserve"))
			{
				try
				{
					String url = String.Format("http://127.0.0.1:{0}/", arguments.Parameters["removeReserve"]);
					UrlReservation.Delete(new UrlReservation(url));
					exit = true;
				}
				catch (Exception)
				{
					Environment.Exit(-1);
				}
			}

			if (exit)
				return;

			try
			{
				Application.EnableVisualStyles();
				Application.SetCompatibleTextRenderingDefault(false);
				Application.Run(new MainForm());
			}
			finally
			{
				using (IsolatedStorageFileStream stream = isoStore.OpenFile(SETTINGSFILE, FileMode.OpenOrCreate))
				{
					Settings.Save(stream);
				}
			}            
		}

		static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
		{
			ShowException(e.ExceptionObject as Exception);
		}

		static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
		{
			ShowException(e.Exception);
		}

		static void ShowException(Exception ex)
		{            
			if (ex is AggregateException)
			{
				foreach (Exception innerEx in ex.As<AggregateException>().InnerExceptions)
				{
					WriteToLogFile(GenerateExceptionMessage("Unhandled exception", ex));
					MessageBox.Show(String.Format("Unhandled exception: {0}. StackTrace: {1}", innerEx.Message, innerEx.StackTrace), "Unhandled exception",
					                MessageBoxButtons.OK, MessageBoxIcon.Error);
				}
			}
			else
			{
				WriteToLogFile(GenerateExceptionMessage("Unhandled exception", ex));
				MessageBox.Show(String.Format("Unhandled exception: {0}. StackTrace: {1}", ex.Message, ex.StackTrace),
				                "Unhandled exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private static void WriteToLogFile(String message)
		{
			String file = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "log.txt");
			if (File.Exists(file))
			{
				File.AppendAllText(file, message);
			}
			else
			{
				File.WriteAllText(file, message);
			}            
		}

		private static String GenerateExceptionMessage(String messageBody, Exception exception)
		{
			StringBuilder sb = new StringBuilder();
			sb.AppendLine(messageBody);
			if (exception != null)
			{
				sb.AppendFormat("\n\nException: {0}", exception.GetType().Name);
				sb.AppendFormat("\nException Message: {0}", exception.Message);
				sb.AppendFormat("\nStack Trace: {0}", exception.StackTrace);
				sb.AppendFormat("\nSource: {0}", exception.Source);
				Exception baseEx = exception.GetBaseException();
				if (baseEx != exception)
				{
					sb.AppendLine("Base exception:");
					sb.AppendFormat("\nException: {0}", baseEx.GetType().Name);
					sb.AppendFormat("\nException Message: {0}", baseEx.Message);
					sb.AppendFormat("\nStack Trace: {0}", baseEx.StackTrace);
					sb.AppendFormat("\nSource: {0}", baseEx.Source);
					//sb.AppendFormat("\nTargetSite: {0}", baseEx.TargetSite);
				}
			}

			return sb.ToString();
		}
	}
}
